home *** CD-ROM | disk | FTP | other *** search
/ Mac-Source 1994 July / Mac-Source_July_1994.iso / C and C++ / Science⁄Math / VideoToolbox / VideoToolboxSources / SetOnePixel.c < prev    next >
Text File  |  1993-07-09  |  10KB  |  303 lines

  1. /*
  2. SetOnePixel.c
  3. NOTE: These routines are obsolete, retained solely for backward compatibility. 
  4. Use SetPixelsQuickly.c instead, since it's more than ten times faster in 
  5. most applications.
  6.  
  7. These are replacements for the official Apple SetCPixel, etc. Their virtue is
  8. that they're faster (but still slow) and don't translate your index via the
  9. color table. GetxxxPixel & SetxxxPixel all ignore the color spec arrays, giving
  10. you direct access to the unsigned number stored in the pixel (whether 1, 2, 4,
  11. 8, 16, or 32 bits)..
  12.  
  13. SetOnePixel(x,y,value);
  14. value=GetOnePixel(x,y);
  15. They use the current port. x and y are local coordinates.
  16.  
  17. SetPixmapPixel() and GetPixmapPixel() use the specified pixmap or bitmap.
  18.  
  19. SetDevicePixel() and GetDevicePixel() use the specified graphics device (i.e.
  20. monitor).
  21.  
  22. NOTE:
  23. If you are setting many contiguous pixels you will be wasting most of your time
  24. on the call overhead (once per pixel). That's why you should use
  25. SetPixelsQuickly.c instead.
  26.  
  27. These routines (and RectToAddress) do not "move memory", i.e. they don't give the
  28. Memory Manager any pretext for shuffling around the memory allocations, and
  29. change its master pointers. That's why it's OK to dereference the pixmap handle,
  30. i.e. use a local copy of the pixmap's master pointer.
  31.  
  32. All the routines in this file call either SetPixmapPixel or GetPixmapPixel. Both
  33. run fast by caching the information that they get about your Bit/Pixmap from
  34. RectToAddress. SetPixmapPixel and GetPixmapPixel each have their own cache.
  35.  
  36. HISTORY:
  37. 4/4/89    dgp wrote it as SetIPixel.c
  38. 9/8/90    dgp updated to work with 32 bit QuickDraw, if present.
  39. 10/15/90 bf renamed SetIPixelGW.c and modified for drawing to off screen pix maps.
  40. 4/26/92    dgp    Merged the two variants: SetIPixel.c and SetIPixelGW.c to produce the
  41.             new file SetOnePixel.c. 
  42.             Renamed SetIPixelGW to SetPixmapPixel.
  43.             Renamed GetIPixelGW to GetPixmapPixel.
  44.             Renamed SetIPixel to SetDevicePixel.
  45.             Renamed GetIPixel to GetDevicePixel.
  46.             Added SetOnePixel and GetOnePixel.
  47.             Generalized to handle any pixelSize, and accept bitmaps as well
  48.             as pixmaps.
  49. 12/23/92 dgp Doubled the speed of SetPixmapPixel and GetPixmapPixel (and thus sped up
  50.             all the routines that call them) by caching the answers from RectToAddress. 
  51.             The cache doubles the speed, but see CAUTION above.Introduced compile-time 
  52.             flag to optionally disable this new cache.
  53. 1/6/93 dgp    Fixed tiny but disastrous bug in GetPixmapPixel (wasn't saving old x and y).
  54. 1/22/93    dgp    Check more PixMap fields to make sure cache is not stale. Deleted the
  55.             warning about stale caches from the documentation.
  56. 2/7/93    dgp Wrote SetPixelsQuickly.c.
  57. 7/9/93    dgp check for 32-bit addressing capability.
  58. */
  59. #include "VideoToolbox.h"
  60. #define USE_CACHE 1    // true or false
  61.  
  62. void SetOnePixel(int x,int y,unsigned long value)
  63. // Assumes (x,y) is in the local coordinate system of the current port.
  64. {
  65.     WindowPtr window;
  66.     PixMapPtr pm;
  67.     
  68.     GetPort(&window);
  69.     if(x<window->portRect.left || x>=window->portRect.right
  70.         || y<window->portRect.top || y>=window->portRect.bottom)return;
  71.     // Is it a CGrafPort or a GrafPort?
  72.     if(((CGrafPtr)window)->portVersion<0)        // It's a CGrafPort,
  73.         pm = *((CGrafPtr)window)->portPixMap;    // pass pixmap ptr.
  74.     else                                         // It's a GrafPort,
  75.         pm = (PixMapPtr) &window->portBits;        // pass bitmap ptr.
  76.     SetPixmapPixel(pm,x,y,value);
  77. }
  78.  
  79. unsigned long GetOnePixel(x,y)
  80. // Assumes (x,y) is in the local coordinate system of the current port.
  81. {
  82.     WindowPtr window;
  83.     PixMapPtr pm;
  84.     Rect *boundsPtr;
  85.     
  86.     GetPort(&window);
  87.     if(x<window->portRect.left || x>=window->portRect.right
  88.         || y<window->portRect.top || y>=window->portRect.bottom)return 0;
  89.     // Is it a CGrafPort or a GrafPort?
  90.     if(((CGrafPtr)window)->portVersion<0)        // It's a CGrafPort,
  91.         pm = *((CGrafPtr)window)->portPixMap;    // pass pixmap ptr.
  92.     else                                         // It's a GrafPort,
  93.         pm = (PixMapPtr) &window->portBits;        // pass bitmap ptr.
  94.     return GetPixmapPixel(pm,x,y);
  95. }
  96.  
  97. void SetPixmapPixel(register PixMapPtr pmPtr,int x,int y,unsigned long value)
  98. // Pokes a value into a pixel of any size. Accepts either pixmap or bitmap.
  99. // Assumes (x,y) is in the coordinate system of the bit/pixmap.
  100. // Speed is enhanced by reusing the cached information from last time if it's the
  101. // same Pix/Bitmap as last time, i.e. same address, baseAddr,rowBytes, and bounds.
  102. // You can force it to flush its cache by passing a NULL PixMap address.
  103. {
  104.     static PixMapPtr oldPmPtr=(PixMapPtr)-1;
  105.     static int oldX,oldY;
  106.     static short rowBytes,logPixelSize,bitsOffset;
  107.     static unsigned char *pixelPtr;
  108.     static BitMap oldMap;
  109.     int shift;
  110.     unsigned char mask;
  111.     char mode32=true32b;
  112.     Rect r;
  113.     Boolean can32;
  114.     long addrMode=0,error;
  115.  
  116.     error=Gestalt(gestaltAddressingModeAttr,&addrMode);
  117.     can32=!error && (addrMode&(1<<gestalt32BitCapable));    
  118.     if(!USE_CACHE || pmPtr!=oldPmPtr
  119.         || pmPtr->baseAddr!=oldMap.baseAddr 
  120.         || pmPtr->rowBytes!=oldMap.rowBytes 
  121.         || *(long *)&pmPtr->bounds.top!=*(long *)&oldMap.bounds.top
  122.         || *(long *)&pmPtr->bounds.bottom!=*(long *)&oldMap.bounds.bottom){
  123.         // Cache is stale. Get fresh values.
  124.         short pixelSize;
  125.         SetRect(&r,x,y,x+1,y+1);
  126.         pixelPtr=RectToAddress(pmPtr,&r,&rowBytes,&pixelSize,&bitsOffset);
  127.         if(pixelPtr==NULL){
  128.             oldPmPtr=(PixMapPtr)-1;    // invalidate cache
  129.             return;
  130.         }
  131.         oldPmPtr=pmPtr;
  132.         oldMap=*(BitMap *)pmPtr;
  133.         logPixelSize=Log2L(pixelSize);
  134.     }else{
  135.         // Cache is fresh. Merely correct for changes in x and y.
  136.         if(pixelPtr==NULL)return;
  137.         if(logPixelSize<3){
  138.             register long bits;
  139.             bits=bitsOffset+(long)(x-oldX)<<logPixelSize;
  140.             pixelPtr+=bits>>3;
  141.             bitsOffset=bits&7;
  142.         }else pixelPtr+=(x-oldX)<<(logPixelSize-3);
  143.         if(y!=oldY)pixelPtr+=(long)(y-oldY)*rowBytes;
  144.     }
  145.     if(can32)SwapMMUMode(&mode32);
  146.     switch(logPixelSize){
  147.         register unsigned char val;
  148.     case 0:
  149.         shift=8-1-bitsOffset;    // from right, instead of from left
  150.         mask=1<<shift;
  151.         val=((unsigned char)value<<shift)&mask;
  152.         mask=~mask;
  153.         *pixelPtr= *pixelPtr & mask | (unsigned char)val;
  154.         break;
  155.     case 1:
  156.         shift=8-2-bitsOffset;    // from right, instead of from left
  157.         mask=3<<shift;
  158.         val=((unsigned char)value<<shift)&mask;
  159.         mask=~mask;
  160.         *pixelPtr= *pixelPtr & mask | (unsigned char)val;
  161.         break;
  162.     case 2:
  163.         shift=8-4-bitsOffset;    // from right, instead of from left
  164.         mask=15<<shift;
  165.         val=((unsigned char)value<<shift)&mask;
  166.         mask=~mask;
  167.         *pixelPtr= *pixelPtr & mask | (unsigned char)val;
  168.         break;
  169.     case 3:
  170.         *pixelPtr=value;
  171.         break;
  172.     case 4:
  173.         *(unsigned short *)pixelPtr=value;
  174.         break;
  175.     case 5:
  176.         *(unsigned long *)pixelPtr=value;
  177.         break;
  178.     }
  179.     if(can32)SwapMMUMode(&mode32);
  180.     oldX=x;
  181.     oldY=y;
  182. }
  183.  
  184. unsigned long GetPixmapPixel(register PixMapPtr pmPtr,int x,int y)
  185. // Returns the contents of a pixel of any size. Accepts either pixmap or bitmap.
  186. // Assumes (x,y) is in the coordinate system of the bit/pixmap.
  187. // Speed is enhanced by reusing the cached information from last time if it's the
  188. // same Pix/Bitmap as last time, i.e. same address, baseAddr,rowBytes, and bounds.
  189. // You can force it to flush its cache by passing a NULL PixMap address.
  190. {
  191.     static PixMapPtr oldPmPtr=(PixMapPtr)-1;
  192.     static int oldX,oldY;
  193.     static short rowBytes,logPixelSize,bitsOffset;
  194.     static unsigned char *pixelPtr;
  195.     static BitMap oldMap;
  196.     int shift;
  197.     unsigned char mask;
  198.     char mode32=true32b;
  199.     Rect r;
  200.     unsigned long value;
  201.     Boolean can32;
  202.     long addrMode=0,error;
  203.  
  204.     error=Gestalt(gestaltAddressingModeAttr,&addrMode);
  205.     can32=!error && (addrMode&(1<<gestalt32BitCapable));
  206.     if(!USE_CACHE || pmPtr!=oldPmPtr
  207.         || pmPtr->baseAddr!=oldMap.baseAddr 
  208.         || pmPtr->rowBytes!=oldMap.rowBytes 
  209.         || *(long *)&pmPtr->bounds.top!=*(long *)&oldMap.bounds.top
  210.         || *(long *)&pmPtr->bounds.bottom!=*(long *)&oldMap.bounds.bottom){
  211.         // Cache is stale. Get fresh values.
  212.         short pixelSize;
  213.         
  214.         SetRect(&r,x,y,x+1,y+1);
  215.         pixelPtr=RectToAddress(pmPtr,&r,&rowBytes,&pixelSize,&bitsOffset);
  216.         if(pixelPtr==NULL){
  217.             oldPmPtr=(PixMapPtr)-1;    // invalidate cache
  218.             return;
  219.         }
  220.         oldPmPtr=pmPtr;
  221.         oldMap=*(BitMap *)pmPtr;
  222.         logPixelSize=Log2L(pixelSize);
  223.     }else{
  224.         // Is already in cache. Merely correct for changes in x and y.
  225.         if(pixelPtr==NULL)return;
  226.         if(logPixelSize<3){
  227.             register long bits;
  228.             bits=bitsOffset+(long)(x-oldX)<<logPixelSize;
  229.             pixelPtr+=bits>>3;
  230.             bitsOffset=bits&7;
  231.         }else pixelPtr+=(x-oldX)<<(logPixelSize-3);
  232.         if(y!=oldY)pixelPtr+=(long)(y-oldY)*rowBytes;
  233.     }
  234.     if(can32)SwapMMUMode(&mode32);
  235.     switch(logPixelSize){
  236.     case 0:
  237.         shift=8-1-bitsOffset;    // from right, instead of from left
  238.         value=*pixelPtr>>shift & 1;
  239.         break;
  240.     case 1:
  241.         shift=8-2-bitsOffset;    // from right, instead of from left
  242.         value=*pixelPtr>>shift & 3;
  243.         break;
  244.     case 2:
  245.         shift=8-4-bitsOffset;    // from right, instead of from left
  246.         value=*pixelPtr>>shift & 15;
  247.         break;
  248.     case 3:
  249.         value=*pixelPtr;
  250.         break;
  251.     case 4:
  252.         value=*(unsigned short *)pixelPtr;
  253.         break;
  254.     case 5:
  255.         value=*(unsigned long *)pixelPtr;
  256.         break;
  257.     }
  258.     if(can32)SwapMMUMode(&mode32);
  259.     oldX=x;
  260.     oldY=y;
  261.     return value;
  262. }
  263.  
  264. void SetDevicePixel(GDHandle device,int x,int y,unsigned long value)
  265. // Assumes (x,y) is relative to the upper left hand corner of the screen.
  266. {
  267.     if(device==NULL)return;
  268.     x+=(*(*device)->gdPMap)->bounds.left;
  269.     y+=(*(*device)->gdPMap)->bounds.top;
  270.     SetPixmapPixel(*(*device)->gdPMap,x,y,value);
  271. }
  272.  
  273. unsigned long GetDevicePixel(GDHandle device,int x,int y)
  274. // Assumes (x,y) is relative to the upper left hand corner of the screen.
  275. {
  276.     if(device==NULL)return;
  277.     x+=(*(*device)->gdPMap)->bounds.left;
  278.     y+=(*(*device)->gdPMap)->bounds.top;
  279.     return GetPixmapPixel(*(*device)->gdPMap,x,y);
  280. }
  281.  
  282. /*
  283. // Slightly faster than RectToAddress, but much less general. 
  284. // Requires 8-bit pixelSize. It will give wrong answer when
  285. // the pixmap is derived from a window in a multi-screen environment.
  286. unsigned char *GetPixmapPixelAddress(PixMapPtr pmPtr,int x,int y)
  287. {
  288.     register unsigned char *pixelPtr;
  289.     
  290.     if(!(pmPtr->rowBytes & 0x8000) || pmPtr->pixelSize != 8) {
  291.         PrintfExit("GetPixmapPixelAddress(): sorry, I require 8 bits/pixel.\007\n");
  292.     }
  293.     if(x<pmPtr->bounds.left || x>=pmPtr->bounds.right
  294.         || y<pmPtr->bounds.top || y>=pmPtr->bounds.bottom)return NULL;
  295.     x-=pmPtr->bounds.left;
  296.     y-=pmPtr->bounds.top;
  297.     pixelPtr=(unsigned char *)pmPtr->baseAddr;
  298.     pixelPtr+=y*(long)(pmPtr->rowBytes & 0x1fff);
  299.     pixelPtr+=x;
  300.     return pixelPtr;
  301. }
  302. */
  303.